package com.own.business.system.account.business.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.own.business.system.account.business.hook.SystemUserTextRegisterMethodHook;
import com.own.business.system.account.business.service.SystemAccountService;
import com.own.business.system.account.common.base.BaseAccountType;
import com.own.business.system.account.common.core.AccountLogoutSpringHook;
import com.own.business.system.account.entity.SystemAccount;
import com.own.business.system.account.mapper.SystemAccountMapper;
import com.own.component.common.exception.BusinessSimpleException;
import com.own.component.common.util.encrypt.EncryptUtil;
import com.own.exception.ExceptionEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.function.Supplier;

/**
 * SystemAccountServiceImpl
 *
 * @author chenxueli
 * @date 2022-09-10 16:11:00
 */
@Slf4j
@Service
public class SystemAccountServiceImpl implements SystemAccountService {

    @Resource
    private SystemAccountMapper systemAccountMapper;

    @Resource
    private AccountLogoutSpringHook accountLogoutSpringHook;
    @Resource
    private SystemUserTextRegisterMethodHook systemUserTextRegisterMethodHook;

    /**
     * 登录
     *
     * @param account     账号信息
     * @param type        账号类型
     * @param accountType 账号类型 1=普通用户 2=管理员
     * @return 登录的用户id信息
     */
    @Override
    public Long login(String account, BaseAccountType type, int accountType) {
        var wrapper = new LambdaQueryWrapper<SystemAccount>()
                .eq(SystemAccount::getAccount, account)
                .eq(SystemAccount::getType, type.type())
                .eq(SystemAccount::getAccountType, accountType)
                .eq(SystemAccount::getEnable, 1);
        var po = systemAccountMapper.selectOne(wrapper);
        if (po == null) {
            throw new BusinessSimpleException("账号或密码错误");
        }
        return po.getFkUserId();
    }

    /**
     * 登录
     *
     * @param account     账号信息
     * @param password    密码（未加密的密码）
     * @param type        账号类型
     * @param accountType 账号类型 1=普通用户 2=管理员
     * @return 登录的用户id信息
     */
    @Override
    public Long login(String account, String password, BaseAccountType type, int accountType) {
        if (StringUtils.isBlank(password)) {
            throw new BusinessSimpleException(ExceptionEnum.Login.PASSWORD_BLANK);
        }
        // 去账号表查询信息
        var po = get(account, type, accountType);
        if (po != null) {
            // 比较密码信息
            if (!EncryptUtil.MD5.encrypt(password).equals(po.getPassword())) {
                throw new BusinessSimpleException(ExceptionEnum.Login.PASSWORD_ERROR);
            }
            // 禁用信息验证
            if (po.getEnable() == 0) {
                throw new BusinessSimpleException(ExceptionEnum.Login.ACCOUNT_BAN);
            }
            return po.getFkUserId();
        }
        // 调用前置信息
        var userId = systemUserTextRegisterMethodHook.beforeTextLogin(account, password, accountType);
        if (userId == null) {
            throw new BusinessSimpleException(ExceptionEnum.Login.PASSWORD_ERROR_BEFORE_LOGIN);
        }
        return userId;
    }

    /**
     * 查询账号信息
     *
     * @param account     账号信息
     * @param type        账号类型
     * @param accountType 账号类型 1=普通用户 2=管理员
     * @return 账号信息
     */
    @Override
    public SystemAccount get(String account, BaseAccountType type, int accountType) {
        var wrapper = new LambdaQueryWrapper<SystemAccount>()
                .eq(SystemAccount::getAccount, account)
                .eq(SystemAccount::getAccountType, accountType)
                .eq(SystemAccount::getType, type.type());
        return systemAccountMapper.selectOne(wrapper);
    }

    /**
     * 查询账号信息
     *
     * @param userId 用户id
     * @param type   账号类型
     * @return 账号信息
     */
    @Override
    public SystemAccount get(Long userId, BaseAccountType type) {
        var wrapper = new LambdaQueryWrapper<SystemAccount>()
                .eq(SystemAccount::getFkUserId, userId)
                .eq(SystemAccount::getType, type.type());
        return systemAccountMapper.selectOne(wrapper);
    }

    /**
     * 注册账号信息
     *
     * @param account     账号信息
     * @param password    密码（未加密的密码）
     * @param type        账号类型
     * @param accountType 账号类型 1=普通用户 2=管理员
     * @param userId      用户id
     * @return 是否注册成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(String account, String password, BaseAccountType type, int accountType, Long userId) {
        // 查询是否已经注册过了
        var old = get(account, type, accountType);
        if (old != null) {
            log.error("账号已经存在了，账号信息: {}", old.getId());
            return false;
        }
        var po = new SystemAccount();
        po.setAccount(account);
        po.setPassword(StringUtils.isBlank(password) ? null : EncryptUtil.MD5.encrypt(password));
        po.setType(type.type());
        po.setFkUserId(userId);
        po.setAccountType(accountType);
        po.setEnable(1);
        return systemAccountMapper.insert(po) == 1;
    }

    /**
     * 修改账号绑定的用户
     *
     * @param account     账号信息
     * @param type        账号类型
     * @param accountType 账号类型 1=普通用户 2=管理员
     * @param userId      用户id
     * @return 是否修改成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean change(String account, BaseAccountType type, int accountType, Long userId) {
        // 查询当前用户是否绑定过同类型的账号
        {
            var old = get(userId, type);
            if (old != null) {
                log.error("当前用户信息已经绑定过同类型的账号了，账号信息: {}", JSON.toJSONString(old));
                return false;
            }
        }
        var old = get(account, type, accountType);
        if (old == null) {
            log.error("待绑定的账号信息不存在：{},{}", account, type);
            return false;
        }
        old.setFkUserId(userId);
        return systemAccountMapper.updateById(old) == 1;
    }

    /**
     * 修改账号的密码
     *
     * @param id       账号主键id
     * @param password 密码（未加密的密码）
     * @return 是否修改成功
     */
    @Override
    public boolean changePassword(Long id, String password) {
        if (StringUtils.isBlank(password)) {
            throw new BusinessSimpleException(ExceptionEnum.Form.PASSWORD_BLANK);
        }
        var newPassword = EncryptUtil.MD5.encrypt(password);
        var wrapper = new LambdaUpdateWrapper<SystemAccount>()
                .eq(SystemAccount::getId, id)
                .set(SystemAccount::getPassword, newPassword);
        systemAccountMapper.update(null, wrapper);
        return true;
    }

    /**
     * 当前类型是否拥有密码
     *
     * @param userId 用户id
     * @param type   账号类型
     * @return 是否拥有密码
     */
    @Override
    public boolean hasPassword(Long userId, BaseAccountType type) {
        var wrapper = new LambdaQueryWrapper<SystemAccount>()
                .eq(SystemAccount::getFkUserId, userId)
                .eq(SystemAccount::getType, type.type())
                .eq(SystemAccount::getEnable, 1);
        return systemAccountMapper.selectCount(wrapper) > 0;
    }

    /**
     * 设置账号的可用状态
     *
     * @param account     账号信息
     * @param type        账号类型
     * @param accountType 1=普通用户 2=管理员
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void enable(String account, BaseAccountType type, int accountType) {
        enable(() -> get(account, type, accountType));
    }

    /**
     * 设置账号的可用状态
     *
     * @param userId 用户id
     * @param type   账号类型
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void enable(Long userId, BaseAccountType type) {
        enable(() -> get(userId, type));
    }

    /**
     * 删除账号信息
     *
     * @param account     账号信息
     * @param type        账号类型
     * @param accountType 1=普通用户 2=管理员
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean remove(String account, BaseAccountType type, int accountType) {
        var wrapper = new LambdaQueryWrapper<SystemAccount>()
                .eq(SystemAccount::getAccount, account)
                .eq(SystemAccount::getAccountType, accountType)
                .eq(SystemAccount::getType, type.type());
        return systemAccountMapper.delete(wrapper) == 1;
    }

    /**
     * 删除账号信息
     *
     * @param userId 用户id
     * @param type   账号类型
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean remove(Long userId, BaseAccountType type) {
        var wrapper = new LambdaQueryWrapper<SystemAccount>()
                .eq(SystemAccount::getFkUserId, userId)
                .eq(SystemAccount::getType, type.type());
        return systemAccountMapper.delete(wrapper) == 1;
    }

    /**
     * 删除账号信息
     *
     * @param userId  用户id
     * @param account 账号信息
     * @param type    账号类型
     * @return 是否删除成功
     */
    @Override
    public boolean remove(Long userId, String account, BaseAccountType type) {
        var wrapper = new LambdaQueryWrapper<SystemAccount>()
                .eq(SystemAccount::getFkUserId, userId)
                .eq(SystemAccount::getAccount, account)
                .eq(SystemAccount::getType, type.type());
        return systemAccountMapper.delete(wrapper) == 1;
    }

    /**
     * 修改账号的密码
     *
     * @param function 获取账号的方法
     * @param password 密码（未加密的密码）
     * @return 是否修改成功
     */
    private boolean changePassword(Supplier<SystemAccount> function, String password) {
        var old = function.get();
        if (old == null) {
            throw new BusinessSimpleException(ExceptionEnum.Form.ACCOUNT_NOT_FOUND);
        }
        if (StringUtils.isBlank(password)) {
            throw new BusinessSimpleException(ExceptionEnum.Form.PASSWORD_BLANK);
        }
        old.setPassword(EncryptUtil.MD5.encrypt(password));
        return systemAccountMapper.updateById(old) == 1;
    }

    /**
     * 修改账号的启用状态
     *
     * @param function 获取账号的方法
     */
    private void enable(Supplier<SystemAccount> function) {
        var old = function.get();
        if (old == null) {
            throw new BusinessSimpleException(ExceptionEnum.Form.ACCOUNT_NOT_FOUND);
        }
        if (old.getEnable() == null) {
            old.setEnable(1);
        } else {
            old.setEnable((old.getEnable() + 1) % 2);
        }
        systemAccountMapper.updateById(old);
    }

    /**
     * 统计账号数量
     *
     * @param userId 用户id
     * @return 账号数量
     */
    @Override
    public long count(Long userId) {
        var wrapper = new LambdaQueryWrapper<SystemAccount>().eq(SystemAccount::getFkUserId, userId);
        return systemAccountMapper.selectCount(wrapper);
    }

    /**
     * 注销账号信息
     *
     * @param userId 用户id
     * @param reason 注销原因
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void logout(Long userId, String reason) {
        if (StringUtils.isNotBlank(reason)) {
            var wrapper = new LambdaUpdateWrapper<SystemAccount>().eq(SystemAccount::getFkUserId, userId).set(SystemAccount::getMemo, reason);
            systemAccountMapper.update(null, wrapper);
        }
        // 删除所有的账号数据信息
        var wrapper = new LambdaQueryWrapper<SystemAccount>().eq(SystemAccount::getFkUserId, userId);
        systemAccountMapper.delete(wrapper);
        // 执行注销账号的后置处理
        accountLogoutSpringHook.run(userId, reason);
    }

}
